package Schiffeversenken;

import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import javax.microedition.lcdui.*;

public class Battleground extends CustomItem implements ItemCommandListener
{
    // members
    private Command     _continueCommand;

    private Display         _display;
    private Timer           _timer;
    private int             _timerCount = 0;
    private TimerTickEvent  _timerTickEvent;

    private Ship[]      _ships;
    private Field[]     _fields;
    private Enemy       _enemy;
    private int[][]     _shots  = new int[GameInstance.COLS][GameInstance.ROWS];     // key1: x-Coord.   key2: y-Coord.  value: -1...water, +1...hit

    private String[]    _coordNamesHorizontal;
    
    private int _rows           = GameInstance.ROWS;
    private int _cols           = GameInstance.COLS;
    private int _fieldWidth     = GameInstance.FIELDWIDTH;

    private int _gameState      = 0;    // 0=wait for place ships
                                        // 1=your turn
                                        // 2=wait for enemy shooting, display message "enemy turn", disapears 1 second after enemies turn is known
                                        // 3=enemy shoot, display own map and after some seconds show shot, some seconds go to 4
                                        // 4=display message "your turn", hit any key for continue with game state 1
                                        // 5=wait for enemy placing ships
                                        // 6=display enemy battlefield but don't react on fire-/navigation keys
                                        // 7=final display on game end, next user interaction returns to main screen

    private BMESound _audioHit;
    private BMESound _audioWater;
    private BMESound _audioSunken;
    private BMESound _audioFire;
    private BMESound _audioWin;
    private BMESound _audioLoose;

    /** Returns true if player is currently on turn */
    public boolean IsOnTurn()
    {
        return _gameState == 1;
    }

    public int newState = -1;

    /** Start the gameplay with either its our move or enemy' */
    public void SetState(int state)
    {
        System.out.println("Changing state from " + _gameState + " to " + state);
        switch (state)
        {
            // no 0 (placing ships)
            // no 1 (player shooting -> instead 4 for placer notification)
            // fire
            //case 1:
            //    this._statusText = "Zielen und ...";
            //    break;
            
            // waiting for enemy shot
            case 2:
                this._statusText = "Warten auf Feindbeschuss ...";
                this._messageText = "Warten auf Feindbeschuss ...";

                // HACK: if opponent starts the game we skip to waiting
                // (from waiting for placing ships)
                if (_gameState == 5)
                {
                    this.readyToReceiveIncoming = true;
                }
                break;
            // incoming shot!
            case 3:
                this._statusText = "Volle Deckung!";
                break;
            // notification of player' turn
            case /*4*/1:
                this._statusText = "Zeit zum Angriff!";
                this._messageText = "Zeit zum Angriff!";
                break;
            default:
                System.err.println("ERROR: invalid gameState: " + state);
                return;
        }

        this._gameState = state;
        repaint();
    }

    // only client OR server may be set 
    public BTClient btClient;
    public BTServer btServer;

    private int _aimX           = 0;
    private int _aimY           = 0;
    private int _shipIndex      = 0;

    private String _statusText;
    private String _messageText;

    private Font _font1         = null;
    private Font _font2         = null;

    private boolean _traverseVertical;
    private boolean _traverseHorizontal;
    private boolean _lastShot_sunk;
    private boolean _disableAiming;

    private boolean _victory;
    private boolean _defeated;

    // constructors
    public Battleground (String title, Display d)
    {
        super (title);        
        _display = d;
        
        int interactionMode = getInteractionModes ();
        _traverseHorizontal = ((interactionMode & CustomItem.TRAVERSE_HORIZONTAL) != 0);
        _traverseVertical   = ((interactionMode & CustomItem.TRAVERSE_VERTICAL)   != 0);

        _font1 = Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_PLAIN, Font.SIZE_MEDIUM);
        _font2 = Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_ITALIC, Font.SIZE_SMALL);

        _continueCommand    = new Command("Weiter", Command.SCREEN, 0);
        addCommand(_continueCommand);
        setDefaultCommand(_continueCommand);
        setItemCommandListener(this);

        _audioWater = new BMESound(new String("/sound_waterblub.wav"), new String("audio/x-wav"));
        _audioHit = new BMESound(new String("/sound_expl.wav"), new String("audio/x-wav"));
        _audioSunken = new BMESound(new String("/sound_sunken.wav"), new String("audio/x-wav"));
        _audioFire = new BMESound("/missle_launch.wav", "audio/x-wav");
        
        _audioWin = new BMESound("/sound_victory.wav", "audio/x-wav");
        _audioLoose = new BMESound("/sound_gameover.wav", "audio/x-wav");

        try {window = Image.createImage("message.png");} catch(Exception e){}

        ReInit();
    }
    Image window;


    // public methods
    public void commandAction (Command c, Item i)
    {
        if ( c == _continueCommand )
        {
            repaint();
        }
    }


    // private methods
    private void ReInit()
    {
        _messageText = "";

        // TESTSTART
        _enemy = new Enemy(false);   // KI Enemy
        // TESTEND

        // horizontal Coords
        _coordNamesHorizontal = new String[GameInstance.COLS];
        for(int c = 0; c < _cols; c++)
        {
            char cc = (char) (65+c);
            _coordNamesHorizontal[c] = "" + cc;
        }

        // reset shoots
        for(int x=0; x<GameInstance.COLS; x++)
        {   for(int y=0; y<GameInstance.ROWS; y++)
            {
                _shots[x][y] = 0;
            }
        }

        _statusText = "Platziere dieses Schiff!";

        // generate fields
        _fields = new Field[ _cols*_rows ];
        int n = 0;
        for(int nx = 0; nx < _cols; nx++)
        {   for(int ny = 0; ny < _rows; ny++)
            {
                _fields[n] = new Field(nx, ny);
                n++;
            }
        }

        _ships      = new Ship[5];   // 2x0, 2x1, 1x2
        _shipIndex  = 0;
        _lastShot_sunk = false;

        Ship s1             = new Ship(2, _aimX, _aimY);
        _ships[_shipIndex]  = s1;


        // timer
        _timerCount     = 0;
        _timer          = new Timer();
        /*
        _timerTickEvent = new TimerTickEvent();
        _timer.schedule(_timerTickEvent, 1000);
        */
    }

    final long DEFAULT_TIMER_TIME = 3000;

    private void drawAiming(Graphics g)
    {
        if(_gameState == 0)
        {
            g.setColor(0x99DDFF);

            int shipLength_h = 1;
            int shipLength_v = 1;
            if(_ships[_shipIndex] != null)
            {
                if(_ships[_shipIndex].isHorizontal())
                    shipLength_h = _ships[_shipIndex].getShipLength();
                else
                    shipLength_v = _ships[_shipIndex].getShipLength();

                if(_ships[_shipIndex].isValidPosition(_ships, _shipIndex) == false)
                    g.setColor(0xFF6633);
            }

            int tmpX = (_aimX) * (GameInstance.FIELDWIDTH+1)-1;
            int tmpY = (_aimY) * (GameInstance.FIELDWIDTH+1)-1;

            // upper left corner
            g.drawLine(tmpX, tmpY, tmpX + 4, tmpY);
            g.drawLine(tmpX, tmpY, tmpX, tmpY + 4);

            // lower left corner
            tmpY += (GameInstance.FIELDWIDTH+1) * shipLength_v - 1;
            g.drawLine(tmpX, tmpY+1, tmpX + 4, tmpY+1);
            g.drawLine(tmpX, tmpY+1, tmpX, tmpY - 4);

            // lower right corner
            tmpX += (GameInstance.FIELDWIDTH+1) * shipLength_h - 1;
            g.drawLine(tmpX+1, tmpY+1, tmpX - 4, tmpY+1);
            g.drawLine(tmpX+1, tmpY+1, tmpX+1, tmpY - 4);

            // upper right corner
            tmpY = (_aimY) * (GameInstance.FIELDWIDTH+1) - 1;
            g.drawLine(tmpX+1, tmpY, tmpX - 4, tmpY);
            g.drawLine(tmpX+1, tmpY, tmpX+1, tmpY + 4);
        }
        else
        {
            g.setColor(0x990000);

            int halfWidth = (int)((GameInstance.FIELDWIDTH+1) / 2);

            int tmpX = (_aimX)*(GameInstance.FIELDWIDTH+1) + halfWidth;
            int tmpY = (_aimY)*(GameInstance.FIELDWIDTH+1) - 1;
            g.drawLine(tmpX , 0, tmpX, tmpY + 3);
            g.drawLine(tmpX, tmpY, tmpX + halfWidth, tmpY);

            tmpX = (_aimX+1)*(GameInstance.FIELDWIDTH+1) - 1;
            g.drawLine(tmpX, tmpY, tmpX, tmpY + halfWidth);
            tmpY = tmpY + halfWidth;
            g.drawLine(tmpX, tmpY, tmpX - 3, tmpY);

            g.setColor(0xdd0000);
            halfWidth -= 2;
            g.drawArc(tmpX - ((int)(GameInstance.FIELDWIDTH/2) + (int)(halfWidth/2)), tmpY - (int)(halfWidth/2), halfWidth, halfWidth, 0, 360);

            g.setColor(0x990000);

            halfWidth   = (int)(GameInstance.FIELDWIDTH / 2);
            tmpX        = (_aimX)*(GameInstance.FIELDWIDTH+1) - 1;
            tmpY        = (_aimY)*(GameInstance.FIELDWIDTH+1) + halfWidth;

            g.drawLine(0, tmpY, tmpX + 3, tmpY);
            g.drawLine(tmpX, tmpY, tmpX, tmpY + halfWidth);

            tmpY = (_aimY+1)*(GameInstance.FIELDWIDTH+1) - 1;
            g.drawLine(tmpX, tmpY, tmpX + halfWidth, tmpY);
            tmpX = tmpX + halfWidth;
            g.drawLine(tmpX, tmpY, tmpX, tmpY - 3);
        }
    }


    // overriden methods
    protected int getMinContentHeight ()
    {   return _rows*(_fieldWidth + 1);          }

    protected int getMinContentWidth ()
    {   return _cols*(_fieldWidth + 1);           }

    protected int getPrefContentHeight (int width)
    {   return (_rows)*(_fieldWidth + 1);      }

    protected int getPrefContentWidth (int height)
    {   return (_cols)*(_fieldWidth + 1);       }

    protected void paint (Graphics g, int w, int h)
    {
        // niederlage/sieg
        int treffer_gesamt = 0;
        for(int x=0; x<GameInstance.COLS; x++)
        {   for(int y=0; y<GameInstance.ROWS; y++)
            {
                if(_shots[x][y] > 0)
                {
                    treffer_gesamt++;
                }
            }
        }
        int treffer_max = 0;
        boolean all_sunken = true;
        for (int ns = 0; ns < _ships.length; ns++)
        {
            if (_ships[ns] != null)
            {
                treffer_max += _ships[ns].getShipLength();
                if (!_ships[ns].isSunken())
                    all_sunken = false;
            }
        }
        if (treffer_gesamt >= treffer_max)
            _victory = true;
        if (all_sunken)
            _defeated = true;

        
        
        // _statusText = "Time elapsed: " + _timerCount + "s";
        g.setColor(45, 75, 105);
        g.fillRect(0, 0, _cols*(_fieldWidth+1), _rows*(_fieldWidth+1));

        g.setColor(35, 70, 125);
        /*for(int nx=0; nx <= _cols; nx++)
        {
            if(nx != 0)
                g.drawString(_coordNamesHorizontal[nx-1], (nx*_fieldWidth)+7, 7, 0);

            g.drawLine((nx+1)*_fieldWidth, _fieldWidth-2, (nx+1)*_fieldWidth, (_cols+1)*_fieldWidth);
        }*/

        g.setColor(45, 75, 105);
        /*for(int ny=0; ny <= _rows; ny++)
        {
            if(ny != 0)
                g.drawString(""+ny, 7, (ny*_fieldWidth)+7, 0);

            g.drawLine(_fieldWidth-2, (ny+1)*_fieldWidth, (_rows+1)*_fieldWidth, (ny+1)*_fieldWidth);
        }*/
        // draw Fields
        for (int nf = 0; nf < _fields.length; nf++)
        {
            g.drawImage(_fields[nf].getWaterImage(), (_fields[nf].X())*(_fieldWidth+1), (_fields[nf].Y())*(_fieldWidth+1), 0);
        }
        // draw Ships
        if(_gameState == 0) // placement
        {
            if (_ships != null && _ships[_shipIndex] != null)
            {
                _ships[_shipIndex].setPosition(_aimX, _aimY);
            }

            if(_ships != null)
            {
                for (int ns = 0; ns < _ships.length; ns++)
                {
                    if(_ships[ns] != null)
                        g.drawImage(_ships[ns].getImage(), _ships[ns].XinMatrix(), _ships[ns].YinMatrix(), 0);
                }
            }

            // draw Aiming
            drawAiming(g);

            // draw enemy sunken ships
            /*
            for (int n=0; n<_enemy.getShips().length; n++)
            {
                if (_enemy.getShips()[n].isSunken())
                {
                    //System.out.println("feindl. schiff gesunken");
                    Ship tmp_ship = _enemy.getShips()[n];
                    g.drawImage(tmp_ship.getImage(), tmp_ship.XinMatrix(), tmp_ship.YinMatrix(), 0);
                }
            }*/
        }
        else if(_gameState == 1 ||_gameState == 6)
        {
            // draw own shoots
            for(int x=0; x<GameInstance.COLS; x++)
            {   for(int y=0; y<GameInstance.ROWS; y++)
                {
                    if(_shots[x][y] != 0)
                    {
                        if(_shots[x][y] >= 1)
                        {
                            g.drawImage(Field.getShootSuccessImage(), (x) * (GameInstance.FIELDWIDTH+1), (y) * (GameInstance.FIELDWIDTH+1), 0);
                        }
                        else if(_shots[x][y] == -1)
                        {
                            g.drawImage(Field.getShootFailImage(), (x) * (GameInstance.FIELDWIDTH+1), (y) * (GameInstance.FIELDWIDTH+1), 0);
                        }
                    }
                }
            }

            // draw Aiming
            if (_gameState == 1)
            {
                drawAiming(g);
                if (_lastShot_sunk)
                    g.drawImage(GameInstance.getSunkenMessage(), 0,0,0);
            }
        }
        // wait for enemy (either that he shots or that he places ships)
        else if(_gameState == 2 || _gameState == 5)
        {   
            try
            {
                g.drawImage(window, 0,0, 0);
                g.setColor(0x663300);
                g.setFont(_font2);
                g.drawString(_messageText, 10, 30, 0);
                g.setFont(_font1);
            }
            catch (Exception ex) {} 
        }
        else if(_gameState == 3)
        {
            // own ships
            if(_ships != null)
            {
                for (int ns = 0; ns < _ships.length; ns++)
                {
                    if(_ships[ns] != null)
                        g.drawImage(_ships[ns].getImage(), _ships[ns].XinMatrix(), _ships[ns].YinMatrix(), 0);
                }
            }

            // enemy shots
            for(int x=0; x<GameInstance.COLS; x++)
            {   for(int y=0; y<GameInstance.ROWS; y++)
                {
                    if(_enemy.getShots()[x][y] != 0)
                    {
                        if(_enemy.getShots()[x][y] == 1)
                        {
                            g.drawImage(Field.getShootSuccessImage(), (x) * (GameInstance.FIELDWIDTH+1), (y) * (GameInstance.FIELDWIDTH+1), 0);
                        }
                        else if(_enemy.getShots()[x][y] == -1)
                        {
                            g.drawImage(Field.getShootFailImage(), (x) * (GameInstance.FIELDWIDTH+1), (y) * (GameInstance.FIELDWIDTH+1), 0);
                        }
                    }
                }
            }
        }
        if (_defeated)
        {
            _audioLoose.start();
            try
            {
                Image defeat = Image.createImage("/message_loose.png");
                g.drawImage(defeat, 0,0, 0);
                this.SetState(7);
            }
            catch (Exception ex) {}
        }
        if (_victory)
        {
            try
            {
                Image win = Image.createImage("/message_victory.png");
                g.drawImage(win, 0,0, 0);
                this.SetState(7);
            }
            catch (Exception ex) {}
            _audioWin.start();
        }
        // Status Text
        g.setColor(0xddeeff);
        g.drawString(_statusText, 0, (_rows+1)*GameInstance.FIELDWIDTH + 5, 0);
    }

    protected void keyPressed(int keyCode)
    {
        onAnyKey();

        if (this._gameState == 5)
        {
            // return if we are waiting for game to begin
            return;
        }
        
        switch (keyCode)
        {
            case Canvas.KEY_NUM2:
                onUp();
                break;
            case Canvas.KEY_NUM4:
                onLeft();
                break;
            case Canvas.KEY_NUM6:
                onRight();
                break;
            case Canvas.KEY_NUM8:
                onDown();
                break;
            case Canvas.KEY_NUM5:
                onFire();
                break;
            case Canvas.KEY_POUND:
                onRaute();
                break;
        }

        System.out.println("Pressed: " + keyCode);
    }


    /** 
     * This is called as the opponent has comitted its shot result
     * Result of last shot to the enemy:
     * -1   - no answer received yet
     *  0   - water
     *  1   - hit
     *  2   - hit & sunk
    */
    public void ReceiveShotResult(int lastShotResult)
    {
        // received a shot result
        switch(lastShotResult)
        {
            case 0: // water
                _shots[_aimX][_aimY] = -1;
                _statusText = "... Wasser :(";
                this._audioWater.start();

                // display enemy battlefield but do not accept keys
                this._gameState = 6;

                // display 1 sec - then put to wait for incoming shot
                AfterHitTask newTask = new AfterHitTask();
                newTask.nextState = 2;
                this.afterHitTimer.cancel();
                this.afterHitTimer = new Timer();
                this.afterHitTimer.schedule(newTask, DEFAULT_TIMER_TIME);
                break;
            case 1: // hit
                _shots[_aimX][_aimY] = 1;
                _statusText = "... Treffer!";
                this._audioHit.start();
                break;
            case 2: // sunken
                _shots[_aimX][_aimY] = 2;
                _lastShot_sunk = true;
                _statusText = "VERSENKT!";
                _audioHit.start();
                break;
            default:
                _statusText = "Die Kugel ist verschwunden!";
                break;
        }
        repaint();
        _disableAiming = false;
    }

    protected boolean traverse (int dir, int viewportWidth, int viewportHeight, int[] visRect_inout)
    {
        onAnyKey();

        if( _traverseVertical && _traverseHorizontal )
        {
            switch (dir)
            {
                case Canvas.DOWN:
                    onDown();
                    break;
                case Canvas.UP:
                    onUp();
                    break;
                case Canvas.LEFT:
                    onLeft();
                    break;
                case Canvas.RIGHT:
                    onRight();
                    break;
                case Canvas.FIRE:
                    onFire();
                    break;
                default:
                    // TEST: don't work yet anyway :(
                    Random myRand = new Random(GameInstance.getRandomSeed());
                    _aimX = myRand.nextInt(_cols-1);
                    _aimY = myRand.nextInt(_rows-1);
                    repaint();
                    break;
            }
        }
        else if (_traverseHorizontal || _traverseVertical)
        {
            return false;
        }
        else
        {
            return false;
        }

        visRect_inout[0] = _aimX;
        visRect_inout[1] = _aimY;
        visRect_inout[2] = GameInstance.FIELDWIDTH;
        visRect_inout[3] = GameInstance.FIELDWIDTH;

        return true;
    }

    private void onUp()
    {
        if (!_disableAiming)
        {
            _aimY--;
            if( _aimY < 0 )
                _aimY = _rows-1;
            repaint();
        }
    }
    private void onDown()
    {
        if (!_disableAiming)
        {
            _aimY++;
            if( _aimY >= _rows )
                _aimY = 0;
            repaint();
        }
    }
    private void onLeft()
    {
        if (!_disableAiming)
        {
            _aimX--;
            if( _aimX < 0 )
                _aimX = _cols-1;
            repaint();
        }
    }
    private void onRight()
    {
        if (!_disableAiming)
        {
            _aimX++;
            if( _aimX >= _cols )
                _aimX = 0;
            repaint();
        }
    }

    private boolean onFire()
    {
        switch (_gameState)
        {
            case 0:     // ship placement
                if(_ships[_shipIndex] != null)
                {
                    if(_ships[_shipIndex].isValidPosition(_ships, _shipIndex))
                    {
                        _ships[_shipIndex].placeShip();

                        int newShipType = 0;
                        _shipIndex++;
                        switch ( _shipIndex )
                        {
                            case 0:
                                newShipType = 2;
                                break;
                            case 1:
                            case 2:
                                newShipType = 1;
                                break;
                            case 3:
                            case 4:
                                newShipType = 0;
                                break;
                            default:    // finish!
                                _gameState = 5;
                                System.out.println("Sending BT Placement Done");
                                if (this.btClient != null)
                                {
                                    this.btClient.PlacementDone();
                                }
                                else
                                {
                                    this.btServer.PlacementDone();
                                }
                                _messageText = "Arrr - Wir warten auf\nden Gegner ...";//"Zielen und ...";
                                repaint();
                                return true;
                        }

                        Ship newShip        = new Ship(newShipType, _aimX, _aimY);
                        _ships[_shipIndex]  = newShip;
                        _statusText = "Platziere dieses Schiff!";
                    }
                    else
                    {
                        _statusText = "Da nicht möglich!";
                    }
                }
                break;
            case 1:     // shoot at enemy
                if(_shots[_aimX][_aimY] == 0)
                {
                    _statusText = "FEUER!";
                    repaint();
                    System.out.println("FIRE!");

                    _disableAiming = true;

                    _audioFire.start();

                    boolean shotSent = false;
                    do
                    {
                        System.out.println("Fire loop next try ...");
                        if (this.btClient != null)
                        {
                            shotSent = this.btClient.Shoot(new Position(_aimX, _aimY));
                        }
                        else
                        {
                            shotSent = this.btServer.Shoot(new Position(_aimX, _aimY));
                        }
                        if (!shotSent)
                        {
                            System.out.println("Fire loop waiting ...");
                            try{this.wait(100);}
                            catch (Exception e) {}
                        }
                    } while (!shotSent);

                    // ok - shot is sent ... now go back until result is
                    // received
                    return true;
                }
                else
                {
                    _statusText = "Da ist immernoch nichts!";
                }
                break;
        }
        repaint();

        return true;
    }

    private Timer afterHitTimer = new Timer();

    /*
    public void OnShot(int shotResult)
    {
        

        if(result <= 0)
        {
            _gameState      = 2;
            _messageText    = "Mist daneben...\nAlle Mann in Deckung!\nfeindl.Beschuss...";

            Position pos = _enemy.NextShoot();
            //if(pos != null)
            //{
            //    _enemy.NextShoot();
            //}
            //else
            //{
                _timerCount     = 0;
                _timerTickEvent = new TimerTickEvent();
                _timer.schedule(_timerTickEvent, 1000);
            //}
        }
    }
    */

    private void onRaute()
    {
        switch (_gameState)
        {
            case 0:     // ship placement
                if(_ships[_shipIndex] != null)
                {
                    _ships[_shipIndex].toggleOrientation();
                }
                break;
        }
        repaint();
    }
    private void onAnyKey()
    {
        if (this._gameState == 7)
        {
            // ignore all buttons as only gameInstance may react on 'exit' now
            return;
        }

        if(_lastShot_sunk)
        {
            _lastShot_sunk = false;
            return;
        }
        /*
        if(_messageText.length() > 0) // message
        {
            
        }

        
        if(_gameState == 3)
        {
            if(_enemy.getLastShotResult() == 1)
            {
                _gameState      = 2;
                _messageText    = "Sie haben getroffen...\nAuf neuen Einschlag\nvorbereiten...";

                Position pos = _enemy.NextShoot();
                _timerCount     = 0;
                _timerTickEvent = new TimerTickEvent();
                _timer.schedule(_timerTickEvent, 1000);
            }
            else
            {
                _gameState = 1;
            }
            repaint();

         * */
    }

    
    // static methods
    public static String convertPositionToCoords(Position pos)
    {
        String strReturn;

        String[] _coordNamesHorizontal = new String[GameInstance.COLS];
        for(int c = 0; c < GameInstance.COLS; c++)
        {
            char cc = (char) (65+c);
            _coordNamesHorizontal[c] = "" + cc;
        }

        strReturn = "" + _coordNamesHorizontal[pos.X()] + "," + (pos.Y()+1);

        return strReturn;
    }
    public static Position convertCoordsToPosition(String coords)
    {
        Position positionReturn = new Position();

        String[] _coordNamesHorizontal = new String[GameInstance.COLS];
        for(int c = 0; c < GameInstance.COLS; c++)
        {
            char cc = (char) (65+c);
            _coordNamesHorizontal[c] = "" + cc;
        }

        // TODO

        return positionReturn;
    }

    /** waits for a single incoming shot and performs displaying of it */
    public void EnemyShot(Position pos)
    {        
        // reset incoming message time
        this.readyToReceiveIncoming = false;
        
        // first update battlefield
        int shotResult = _enemy.ShootAt(pos, _ships);

        try {this.afterHitTimer.cancel();}
        catch (Exception e) {}
        AfterHitTask newTask = new AfterHitTask();

        switch (shotResult)
        {
            // water
            case 0:
                _statusText = "Puh, daneben! :)";
                // wait one sec - then put back to attack
                newTask.nextState = 1;
                this._audioWater.start();
                break;
            // hit / hit & sunken
            case 1:
                _statusText = "Treffer!  :(";
                // wait one sec - then put back to 'waiting for incoming...'
                newTask.nextState = 2;
                this._audioHit.start();
          
                break;
            case 2:
                _statusText = "Versenkt!  :(";
                // wait one sec - then put back to 'waiting for incoming...'
                newTask.nextState = 2;
                _audioHit.start();
                break;
            default:
                System.err.println("unkown shot result: " + shotResult);
                break;
        }

        // visualize shot
        this.SetState(3);

        this.afterHitTimer.cancel();
        this.afterHitTimer = new Timer();
        this.afterHitTimer.schedule(newTask, DEFAULT_TIMER_TIME);


        // then send result to opponent
        boolean sent = false;
        do
        {
            System.out.println("sending response ...");
            if (btClient != null)
            {
                sent = btClient.SendShotResult(shotResult, pos);
            }
            else
            {
                sent = btServer.SendShotResult(shotResult, pos);
            }
            if (!sent)
            {
                try {wait(500);}
                catch (Exception e) {}
            }
        } while (!sent);
    }

    public boolean readyToReceiveIncoming = false;


    // private classes
    private class TimerTickEvent extends TimerTask
    {
        public final void run()
        {
            _timerCount++;
            
            if(_gameState == 2)
            {
                _messageText    = "Alle Mann in Deckung!\nfeindl.Beschuss... "/*+(GameInstance.AWAIT_ENEMY_SHOOT-_timerCount)*/;
                repaint();

                // if player vs. player this will wait until enemy has made a shot
                Position pos = _enemy.NextShoot();
                if (pos != null)
                {
                    _enemy.ShootAt(pos, _ships);
                    System.out.println("NextShot x: " + pos.X() + " y: " + pos.Y());
                    _gameState = 3;
                }
                else
                {
                    if(_timerCount < GameInstance.AWAIT_ENEMY_SHOOT)
                    {
                        _timerTickEvent = new TimerTickEvent();
                        _timer.schedule(_timerTickEvent, 1000);
                    }
                }
            }
        }
    }

    /**
     * This TimerTask will change state from
     *
     * 6 (shooting) to 2 (waiting for enemy shot) after player hit the water
     * 
     * OR from
     *
     * 3 (receiving shot) to 1 (shooting) after enemy hit the water
     *
     * OR from
     *
     * 3 (receiving shot) to 2 (waiting for incoming shot) after enemy hit ship.
     */
    private class AfterHitTask extends TimerTask
    {
        public int nextState = -1;

        public final void run()
        {
            System.out.println("AfterHitTask wake up. Changing state from " + _gameState + " to " + nextState);
            if (_gameState == 6 || _gameState == 3)
            {
                if (nextState == 2)
                {
                    // change to waiting for enemy shot
                    SetState(nextState);
                    readyToReceiveIncoming = true;
                }
                else if (nextState == 1)
                {
                    // attack!
                    SetState(nextState);
                    readyToReceiveIncoming = true;
                }
            }
        }
    }
}
